iT邦幫忙

2021 iThome 鐵人賽

DAY 9
0

安安!前幾天講了怎麼在專案裡用些 data fetching functions 做 pre-rendering。不過如果想要直接在 client-side 抓取資料呢?有什麼方法?~ 今天跟大家分享一個 data fetching (抓取資料) 的 library,SWR

SWR

什麼是 SWR

SWRstale-while-revalidate 的簡稱,意思是我們抓取資料的時候,會先拿到 cache 裡 (stale / 舊資料) 的,然後在背後去發請求抓取資料 (revalidate),再回傳最新的資料。SWR 是一個提供抓取資料功能的 react hooks library,沒錯,他是 react hooks!

為什麼要用 SWR

在 client-side 抓取資料算簡單,可是也必須注意一些事情,例如重複呼叫某 API。有了 SWR 之後,我們不用再擔心這件事!SWR 幫我們做這些:

  • 可重複使用的 react hooks
  • 管理 cache
  • 避免重複發 API 請求
  • 定時抓取資料,讓體驗很像 real-time (即時)
  • 遇到錯誤時,重試發請求
  • 支援 SSG,ISR,SSR
  • 支援 TypeScript

Setup

很簡單~ 在專案的目錄下,輸入以下指令:

yarn add swr
# or
npm install swr

裝完就可以這樣使用:

import useSWR from 'swr'

function User() {
  // Github API: https://api.github.com/users/vercel
  const { data, error } = useSWR('https://api.github.com/users/vercel', fetcher)

  if (error) return <div>發生錯誤 :o</div>
  if (!data) return <div>loading...</div>
  return <div>Hi {data.name}!</div> // Hi Vercel!
}

這裡 useSWR hooks 接收兩個 parameters,keyfetcher function。

  • keySWR 會根據這 key 做 cache,通常是請求的 API URL

  • fetcher:去做抓取的 function,這 function 接收 key 當 parameter 然後回傳 data (資料)。可以用一般的 fetchaxios,或是 GraphQL,只要可以用 key 去抓取和回傳資料都可以

    const fetcher = (...args) => fetch(...args).then(res => res.json())
    

做成 Reusable Custom Hooks

上面那段 code 只能抓取 vercel 這 Github user 的資料,如果我們想抓其他人的資料呢?要複製貼上嗎?不用~ 我們可以做 React custom hook:

function useUser (id) {
  const { data, error } = useSWR(`https://api.github.com/users/${id}`, fetcher)

  return {
    user: data,
    isLoading: !error && !data,
    isError: error
  }
}

然後在 React component 裡使用:

// Avatar component
function Avatar ({ id }) {
  const { user, isLoading, isError } = useUser(id)

  if (isLoading) return <Spinner />
  if (isError) return <Error />
  return <img src={user.avatar_url} alt={user.name} />
}

那如果有不只一個 component 需要用到 user 的資料呢?useUser hook 可以在很多 component 裡重複使用喔:

// Info component
function Info ({ id }) {
  const { user, isLoading } = useUser(id)
  if (isLoading) return <Spinner />
  if (isError) return <Error />
  return <h1>Welcome back, {user.name} (@{user.login})</h1>
}

是不是很方便!而且 SWR 會自動做 cache 還有避免重複發請求,雖然我們使用了 useUser 兩次,可是實際上我們只發一次 API request 喔!這麼做可以減少 props 傳遞的動作,每個獨立的 component 自己處理資料~

同步資料?

伺服器端或是資料庫裡的資料有可能會變,我們該怎麼拿到最新值?該怎麼跟伺服器做同步?SWR 的 revalidation 機制成為答案!有幾個 revalidate 時機:

  • focus 時 (revalidateOnFocus):這裡的 focus 是指 瀏覽器 tab 的 focus,使用者有沒有正在看該 tab,如果沒有,每次使用者回到這 tab,SWR 會做 revalidate (重新抓取資料),讓使用者看到最新的資料
  • interval (refreshInterval):定時去做 revalidate,只要畫面上有用到這些資料,SWR 會根據我們設定的 interval 去做資料更新,讓畫面看起來有即時更新
  • reconnect 時 (revalidateOnReconnect):使用者有可能會斷線,例如電腦進入睡眠模式,當使用者重新連到網路時,SWR 會做 revalidate 更新資料~
  • 永遠不同步 (useSWRImmutable):以上三種 revalidate 時機會讓資料保持同次的狀態,可是如果資料完全不會變,那何必 revalidate 呢?我們可以把 revalidate 機制關掉,讓 SWR 永遠不做資料同步,只抓一次資料!

Next.jsSWR

看起來都很棒,想要開始用在 Next.js 的專案裡,該怎麼用呢?

Client-side Data Fetching

其實如果想要在瀏覽器端去抓取資料的話,直接用 useSWR 在 component 裡就可以~ 就像上面的 code 一樣,基本上就是在 React components 裡面使用 useSWR 或是 custom SWR hooks 喔!

Pre-rendering

可是 Next.js 又可以做 pre-rendering,例如 SSG 或是 SSR,那還是可以用 SWR 嗎?當然可以的!SWR 是處理 client-side 的資料抓取方式,我們只要可以在 build time 時拿到資料讓頁面不完全是空的,然後 request time 時在瀏覽器再重新抓取最新資料。之前如果用 getStaticProps 或是 getServerSideProps 時,我們都會把 props 傳到 page (頁面) component 裡。可是用 SWR 的方式比較不一樣:

// 一樣在 getStaticProps 抓取資料
export async function getStaticProps () {
  const article = await getArticleFromAPI()
  // 要回傳 fallback 的資料!
  return {
    props: {
      fallback: {
        // 這 key 要跟 useSWR 用的 key 一樣喔~
        '/api/article': article
      }
    }
  }
}

// Article component
function Article() {
  // 因為 fallback 有包含 `/api/article` 這 key,
  // data 預設值會是 fallback 裡設定的值
  // 當使用者在瀏覽器看到這畫面時,SWR 會抓取最新料
  const { data } = useSWR('/api/article', fetcher)
  return <h1>{data.title}</h1>
}

// Page component 收到 getStaticProps 回傳的 props.fallback
export default function Page({ fallback }) {
  // SWRConfig 去做設定,在這裡設定 fallback 值
  return (
    <SWRConfig value={{ fallback }}>
      <Article />
    </SWRConfig>
  )
}

所以產生頁面時會先塞資料進 HTML 檔案,不過當使用者在瀏覽器看到這畫面時,SWR 會抓取最新料,更新 HTML 裡原本的內容。

小結

如果大家對於 client-side data fetching 有興趣或需求,真的可以去看看 SWR!簡單又方便,還能做 cache,也不用做 props drilling,實在很開心~ 不過我目前也沒有在大專案用過 SWR,所以不太清楚會不會不適用在較複雜的專案Q

祝大家週末愉快!

晚安 <3

看更多


上一篇
#08 實作篇 — 使用 Next.js 的各種 Data Fetching 方式實作小專案 ft. Github API
下一篇
#10 實作篇 — 使用 SWR 抓取和 Cache 資料
系列文
製作你的無程式碼(No-code)個人網頁 ft. Next.js, SWR, 串 Youtube, IG, Github, Notion API ~30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言